package com.xc.btc.util;

import com.alibaba.fastjson.JSON;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;


public class HttpClient {
    private static final String METHOD_POST = "POST";
    private static final String METHOD_GET = "GET";
    public static final String CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";
    public static final String CONTENT_TYPE_JSON = "application/json;charset=utf-8";
    public static final String CONTENT_TYPE_DATA = "multipart/form-data";

    /**
     * POST请求(默认请求参数格式application/json)
     * @param address 访问地址
     * @return
     */
    public static String doPost(String address) {
        return doPost(address, "", CONTENT_TYPE_JSON);
    }

    /**
     * POST请求
     * @param address 访问地址
     * @param contentType 参数格式
     * @return
     */
    public static String doPost(String address, String contentType) {
        return doPost(address, "", contentType);
    }

    /**
     * POST请求(默认请求参数格式application/json)
     * @param address 访问地址
     * @param params 访问参数
     * @return
     */
    public static String doPost(String address, Map<String, Object> params) {
        return doPost(address, JSON.toJSONString(params), CONTENT_TYPE_JSON);
    }

    /**
     * POST请求
     * @param address 访问地址
     * @param params 访问参数
     * @param contentType 参数格式
     * @return
     */
    public static String doPost(String address, Map<String, Object> params, String contentType) {
        return doPost(address, JSON.toJSONString(params), contentType);
    }

    /**
     * POST请求
     * @param address 访问地址
     * @param params 访问参数(Json格式字符串)
     * @param contentType 参数格式
     * @return
     */
    public static String doPost(String address, String params, String contentType) {
        HttpURLConnection connection = getConnectionByPost(address, contentType);
        try {
            // 写入参数
            if (params != null && !"".equals(params) && params.length() > 0) {
                OutputStream outputStream = connection.getOutputStream();
                outputStream.write(params.getBytes(Charset.forName("UTF-8")));
                outputStream.flush();
                outputStream.close();
            }
            // 判断请求是否成功
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                String responseMsg = connection.getResponseMessage();
                throw new RuntimeException(responseMsg);
            }
            // 读取返回数据
            InputStream inputStream = connection.getInputStream();
            String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
                    .collect(Collectors.joining(System.lineSeparator()));
            inputStream.close();
            return result;
        } catch (IOException e) {
            throw new RuntimeException("POST请求发生IO异常");
        } finally {
            // 关闭链接
            connection.disconnect();
        }
    }

    /**
     * Post请求，把结果转换为指定的实体类型
     * @param address
     * @param <W>
     * @return
     */
    public static <W> W doPostToObject(W w, String address) {
        String result = doPost(address);
        if (result != null) {
            w = JSON.parseObject(result, (Class<W>) w.getClass());
            return w;
        }
        return null;
    }

    /**
     * Post请求，把结果转换为指定的实体类型
     * @param address
     * @param params
     * @param <W>
     * @return
     */
    public static <W> W doPostToObject(W w, String address, String params) {
        String result = doPost(address, params);
        if (result != null) {
            w = JSON.parseObject(result, (Class<W>) w.getClass());
            return w;
        }
        return null;
    }

    /**
     * Post请求，把结果转换为指定的实体类型
     * @param address
     * @param params
     * @param contentType
     * @param <W>
     * @return
     */
    public static <W> W doPostToObject(W w, String address, String params, String contentType) {
        String result = doPost(address, params, contentType);
        if (result != null) {
            w = JSON.parseObject(result, (Class<W>) w.getClass());
            return w;
        }
        return null;
    }

    /**
     * Post请求，把结果转换为指定的实体类型
     * @param address
     * @param params
     * @param contentType
     * @param <W>
     * @return
     */
    public static <W> W doPostToObject(W w, String address, Map<String, Object> params, String contentType) {
        String result = doPost(address, params, contentType);
        if (result != null) {
            w = JSON.parseObject(result, (Class<W>) w.getClass());
            return w;
        }
        return null;
    }

    /**
     * Post请求，把结果转换为指定的实体类型
     * @param address
     * @param params
     * @param <W>
     * @return
     */
    public static <W> W doPostToObject(W w, String address, Map<String, Object> params) {
        String result = doPost(address, params);
        if (result != null) {
            w = JSON.parseObject(result, (Class<W>) w.getClass());
            return w;
        }
        return null;
    }

    /**
     * GET请求
     * @param address
     * @return
     */
    public static String doGet(String address) {
        return doGet(address, null);
    }

    /**
     * GET请求
     * @param address 访问地址
     * @param params 参数列表
     * @return
     */
    public static String doGet(String address, Map<String, Object> params) {
        StringBuffer url = new StringBuffer(address);
        if (params != null) {
            try {
                url.append("?");
                Iterator<Map.Entry<String, Object>> iterator = params.entrySet().iterator();
                while (iterator.hasNext()) {
                    Map.Entry<String, Object> entry = iterator.next();
                    url.append(entry.getKey()).append("=").append(URLEncoder.encode(String.valueOf(entry.getValue()),"UTF-8")).append("&");
                }
            } catch (Exception e) {
                throw new RuntimeException("参数编码异常");
            }
        }
        System.out.println(url.toString());
        HttpURLConnection connection = getConnectionByGet(url.toString());
        try {
            // 判断请求是否成功
            int responseCode = connection.getResponseCode();
            if (responseCode != HttpURLConnection.HTTP_OK) {
                String responseMsg = connection.getResponseMessage();
                throw new RuntimeException(responseCode + responseMsg);
            }
            // 读取返回数据
            InputStream inputStream = connection.getInputStream();
            String result = new BufferedReader(new InputStreamReader(inputStream)).lines()
                    .collect(Collectors.joining(System.lineSeparator()));
            inputStream.close();
            return result;
        } catch (IOException e) {
            throw new RuntimeException("GET请求发生IO异常");
        } finally {
            // 关闭链接
            connection.disconnect();
        }
    }

    /**
     * 获取HttpURLConnection对象
     * @param address
     * @return
     */
    private static HttpURLConnection getConnectionByPost(String address, String contentType) {
        try {
            // 1.得到访问地址的URL
            URL url = new URL(address);
            // 2.创建HttpURLConnection对象
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 3.设置请求参数
            // 3.1 设置请求方式
            connection.setRequestMethod(METHOD_POST);
            // 3.2 设置打开链接超时时间（单位: 毫秒）
            connection.setConnectTimeout(30000);
            // 3.3 设置读取超时时间（单位：毫秒）
            connection.setReadTimeout(30000);
            // 3.4 设置是否使用缓存
            connection.setUseCaches(false);
            // 3.5 设置参数放入body中
            connection.setDoOutput(true);
            // 3.6 设置需要读取返回数据
            connection.setDoInput(true);
            // 3.7 设置请求参数格式
            connection.setRequestProperty("Content-type", contentType);
            // 打开通信链接
            connection.connect();
            return connection;
        } catch (Exception e) {
            throw new RuntimeException("POST请求发生异常");
        }
    }

    /**
     * 获取HttpURLConnection对象
     * @param address
     * @return
     */
    private static HttpURLConnection getConnectionByGet(String address) {
        try {
            // 1.得到访问地址的URL
            URL url = new URL(address);
            // 2.创建HttpURLConnection对象
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            // 3.设置请求参数
            // 3.1 设置请求方式
            connection.setRequestMethod(METHOD_GET);
            // 3.2 设置打开链接超时时间（单位: 毫秒）
            connection.setConnectTimeout(30000);
            // 3.3 设置读取超时时间（单位：毫秒）
            connection.setReadTimeout(30000);
            // 打开通信链接
            connection.connect();
            return connection;
        } catch (Exception e) {
            throw new RuntimeException("GET请求发生异常");
        }
    }
}
